<template>
	<div>
		<el-drawer
			v-bind="$attrs"
			v-on="$listeners"
			@opened="onOpen"
			@close="onClose"
		>
			<div style="height: 100%">
				<el-row style="height: 100%; overflow: auto">
					<el-col :md="24" :lg="12" class="left-editor">
						<!-- <div class="setting" title="资源引用" @click="showResource">
              <el-badge :is-dot="!!resources.length" class="item">
                <i class="el-icon-setting" />
              </el-badge>
            </div> -->
						<el-tabs v-model="activeTab" type="card" class="editor-tabs">
							<el-tab-pane name="html">
								<span slot="label">
									<i v-if="activeTab === 'html'" class="el-icon-edit" />
									<i v-else class="el-icon-document" />
									template
								</span>
							</el-tab-pane>
							<el-tab-pane name="js">
								<span slot="label">
									<i v-if="activeTab === 'js'" class="el-icon-edit" />
									<i v-else class="el-icon-document" />
									script
								</span>
							</el-tab-pane>
							<el-tab-pane name="css">
								<span slot="label">
									<i v-if="activeTab === 'css'" class="el-icon-edit" />
									<i v-else class="el-icon-document" />
									css
								</span>
							</el-tab-pane>
						</el-tabs>
						<div
							v-show="activeTab === 'html'"
							id="editorHtml"
							class="tab-editor"
						/>
						<div v-show="activeTab === 'js'" id="editorJs" class="tab-editor" />
						<div
							v-show="activeTab === 'css'"
							id="editorCss"
							class="tab-editor"
						/>
					</el-col>
					<el-col :md="24" :lg="12" class="right-preview">
						<div class="action-bar" :style="{ 'text-align': 'left' }">
							<!-- <span class="bar-btn" @click="runCode">
                <i class="el-icon-refresh" />
                刷新
              </span> -->
							<!-- <span class="bar-btn" @click="exportFile">
                <i class="el-icon-download" />
                导出vue文件
              </span> -->
							<span ref="copyBtn" class="bar-btn copy-btn">
								<i class="el-icon-document-copy" />
								复制代码
							</span>
							<span
								class="bar-btn delete-btn"
								@click="$emit('update:visible', false)"
							>
								<i class="el-icon-circle-close" />
								关闭
							</span>
						</div>
						<parser
							:form-conf="formData"
							style="
								margin-top: 10px;
								height: calc(100% - 43px);
								overflow-y: auto;
							"
						/>
						<!-- <iframe
              v-show="isIframeLoaded"
              ref="previewPage"
              class="result-wrapper"
              frameborder="0"
              src="preview.html"
              @load="iframeLoad"
            /> -->
						<!-- <div
              v-show="!isIframeLoaded"
              v-loading="true"
              class="result-wrapper"
            /> -->
					</el-col>
				</el-row>
			</div>
		</el-drawer>
		<!-- <resource-dialog
      :visible.sync="resourceVisible"
      :origin-resource="resources"
      @save="setResource"
    /> -->
	</div>
</template>
<script>
import { parse } from '@babel/parser'
import parser from '@/components/parser/parser'
import ClipboardJS from 'clipboard'
import { saveAs } from 'file-saver'
import {
	makeUpHtml,
	vueTemplate,
	vueScript,
	cssStyle,
} from '@/components/generator/html'
import { makeUpJs } from '@/components/generator/js'
import { makeUpCss } from '@/components/generator/css'
import { beautifierConf } from '@/utils/index'
// import ResourceDialog from './ResourceDialog'
import loadMonaco from '@/utils/loadMonaco'
import loadBeautifier from '@/utils/loadBeautifier'

const editorObj = {
	html: null,
	js: null,
	css: null,
}
const mode = {
	html: 'html',
	js: 'javascript',
	css: 'css',
}
let beautifier
let monaco

export default {
	components: { parser },
	props: {
		formData: {
			type: Object,
			default: () => {},
		},
		generateConf: {
			type: Object,
			default: () => {},
		},
	},
	data() {
		return {
			activeTab: 'html',
			htmlCode: '',
			jsCode: '',
			cssCode: '',
			codeFrame: '',
			isIframeLoaded: false,
			isInitcode: false, // 保证open后两个异步只执行一次runcode
			isRefreshCode: false, // 每次打开都需要重新刷新代码
			resourceVisible: false,
			scripts: [],
			links: [],
			monaco: null,
		}
	},
	computed: {
		resources() {
			return this.scripts.concat(this.links)
		},
	},
	watch: {},
	created() {},
	mounted() {
		window.addEventListener('keydown', this.preventDefaultSave)
		const clipboard = new ClipboardJS('.copy-btn', {
			text: () => {
				const codeStr = this.generateCode()
				this.$notify({
					title: '成功',
					message: '代码已复制到剪切板，可粘贴。',
					type: 'success',
				})
				return codeStr
			},
		})
		clipboard.on('error', () => {
			this.$message.error('代码复制失败')
		})
	},
	beforeDestroy() {
		window.removeEventListener('keydown', this.preventDefaultSave)
	},
	methods: {
		preventDefaultSave(e) {
			if (e.key === 's' && (e.metaKey || e.ctrlKey)) {
				e.preventDefault()
			}
		},
		onOpen() {
			const { type } = this.generateConf
			this.htmlCode = makeUpHtml(this.formData, type)
			this.jsCode = makeUpJs(this.formData, type)
			this.cssCode = makeUpCss(this.formData)

			loadBeautifier(btf => {
				beautifier = btf
				this.htmlCode = beautifier.html(this.htmlCode, beautifierConf.html)
				this.jsCode = beautifier.js(this.jsCode, beautifierConf.js)
				this.cssCode = beautifier.css(this.cssCode, beautifierConf.html)

				loadMonaco(val => {
					monaco = val
					this.setEditorValue('editorHtml', 'html', '')
					this.setEditorValue('editorJs', 'js', '')
					this.setEditorValue('editorCss', 'css', '')
					this.setEditorValue('editorHtml', 'html', this.htmlCode)
					this.setEditorValue('editorJs', 'js', this.jsCode)
					this.setEditorValue('editorCss', 'css', this.cssCode)
					if (!this.isInitcode) {
						this.isRefreshCode = true
						this.isIframeLoaded && (this.isInitcode = true) && this.runCode()
					}
				})
			})
		},
		onClose() {
			this.isInitcode = false
			this.isRefreshCode = false
		},
		iframeLoad() {
			if (!this.isInitcode) {
				this.isIframeLoaded = true
				this.isRefreshCode && (this.isInitcode = true) && this.runCode()
			}
		},
		setEditorValue(id, type, codeStr) {
			if (editorObj[type]) {
				editorObj[type].setValue(codeStr)
			} else {
				editorObj[type] = monaco.editor.create(document.getElementById(id), {
					value: codeStr,
					theme: 'vs-dark',
					language: mode[type],
					automaticLayout: true,
				})
			}
			// ctrl + s 刷新
			editorObj[type].onKeyDown(e => {
				if (e.keyCode === 49 && (e.metaKey || e.ctrlKey)) {
					this.runCode()
				}
			})
		},
		runCode() {
			const jsCodeStr = editorObj.js.getValue()
			try {
				const ast = parse(jsCodeStr, { sourceType: 'module' })
				const astBody = ast.program.body
				if (astBody.length > 1) {
					this.$confirm(
						'js格式不能识别，仅支持修改export default的对象内容',
						'提示',
						{
							type: 'warning',
						},
					)
					return
				}
				if (astBody[0].type === 'ExportDefaultDeclaration') {
					// const postData = {
					//   type: 'refreshFrame',
					//   data: {
					//     generateConf: this.generateConf,
					//     html: editorObj.html.getValue(),
					//     js: jsCodeStr.replace(exportDefault, ''),
					//     css: editorObj.css.getValue(),
					//     scripts: this.scripts,
					//     links: this.links
					//   }
					// }
					// this.$refs.previewPage.contentWindow.postMessage(postData, location.origin)
				} else {
					this.$message.error('请使用export default')
				}
			} catch (err) {
				this.$message.error(`js错误：${err}`)
				console.error(err)
			}
		},
		generateCode() {
			const html = vueTemplate(
				editorObj.html.getValue(),
				this.generateConf.type,
			)
			const script = vueScript(
				editorObj.js.getValue(),
				null,
				this.generateConf.type,
			)
			const css = cssStyle(editorObj.css.getValue(), this.generateConf.type)
			return beautifier.html(html + script + css, beautifierConf.html)
		},
		exportFile() {
			this.$prompt('文件名:', '导出文件', {
				inputValue: `${+new Date()}.vue`,
				closeOnClickModal: false,
				inputPlaceholder: '请输入文件名',
			}).then(({ value }) => {
				if (!value) value = `${+new Date()}.vue`
				const codeStr = this.generateCode()
				const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
				saveAs(blob, value)
			})
		},
		showResource() {
			this.resourceVisible = true
		},
		setResource(arr) {
			const scripts = []
			const links = []
			if (Array.isArray(arr)) {
				arr.forEach(item => {
					if (item.endsWith('.css')) {
						links.push(item)
					} else {
						scripts.push(item)
					}
				})
				this.scripts = scripts
				this.links = links
			} else {
				this.scripts = []
				this.links = []
			}
		},
	},
}
</script>

<style lang="scss" scoped>
@import './styles/mixin.scss';
.tab-editor {
	position: absolute;
	top: 33px;
	bottom: 0;
	left: 0;
	right: 0;
	font-size: 14px;
}
.left-editor {
	position: relative;
	height: 100%;
	background: #1e1e1e;
	overflow: hidden;
}
.setting {
	position: absolute;
	right: 15px;
	top: 3px;
	color: #a9f122;
	font-size: 18px;
	cursor: pointer;
	z-index: 1;
}
.right-preview {
	height: 100%;
	.result-wrapper {
		height: calc(100vh - 33px);
		width: 100%;
		overflow: auto;
		padding: 12px;
		box-sizing: border-box;
	}
}
@include action-bar;
::v-deep .el-drawer__header {
	display: none;
}
</style>
